package InstanceZone

import (
	codecs "sanguo/codec/cs"
	"sanguo/node/common/attr"
	"sanguo/node/common/com_type"
	"sanguo/node/common/transaction"
	"sanguo/node/node_game"
	"sanguo/node/node_game/module/role"
	"sanguo/node/node_game/user"
	table_BattleLevel "sanguo/node/table/excel/table/BattleLevel"
	cs_message "sanguo/protocol/cs/message"
	"time"

	"github.com/golang/protobuf/proto"
)

type transactionEnterInstanceZone struct {
	transaction.TransactionBase
	user    *user.User
	req     *codecs.Message
	resp    *cs_message.EnterInstanceZoneToC
	errcode cs_message.EnumType
}

func (this *transactionEnterInstanceZone) GetModuleName() string {
	return "InstanceZone"
}

func (this *transactionEnterInstanceZone) GetReplyMsg() proto.Message {
	return &cs_message.EnterInstanceZoneToC{}
}

func (this *transactionEnterInstanceZone) SetExpiredTime(expired time.Time) {
	this.Expired = expired
}

func (this *transactionEnterInstanceZone) GetExpiredTime() time.Time {
	return this.Expired
}

func (this *transactionEnterInstanceZone) Begin() {
	msg := this.req.GetData().(*cs_message.EnterInstanceZoneToS)
	roleModule := this.user.GetModuleByName("role").(*role.RoleModule)
	role := roleModule.CurrentRole()

	if role == nil || !role.IsRoleModleData() {
		node_game.Infoln(this.user.GetUserID(), "EnterInstanceZone fail : no selectRole ")
		this.errcode = cs_message.EnumType_ERROR
		this.user.EndTrans(this)
		return
	}
	node_game.Infof("%s %d Call EnterInstanceZone id:%d ", role.GetUserID(), role.GetID(), msg.GetInstanceZoneID())

	if role.GetInstanceZone() != nil {
		node_game.Infoln(role.GetUserID(), role.GetID(), "EnterCampaign fail :instanceZone is not nil")
		this.errcode = cs_message.EnumType_ERROR
		this.user.EndTrans(this)
		return
	}

	IZDef := table_BattleLevel.Table_.IDMap[msg.GetInstanceZoneID()]
	if IZDef == nil {
		node_game.Infoln(role.GetUserID(), role.GetID(), "EnterInstanceZone fail:IZDef is nil")
		this.errcode = cs_message.EnumType_ERROR
		this.user.EndTrans(this)
		return
	}

	if IZDef.Type == com_type.InstanceZone_YhBattleGround {
		battleGround := role.GetBattleGround()
		if battleGround == nil {
			node_game.Infoln(role.GetUserID(), role.GetID(), "EnterInstanceZone fail:no  battleGround")
			this.errcode = cs_message.EnumType_ERROR
			this.user.EndTrans(this)
			return
		}

		//初始化InstanceZone
		battleLevel := battleGround.GetBattleLevelByIndex(battleGround.CurrentEnter)
		if battleLevel.BattleLevelID != msg.GetInstanceZoneID() {
			node_game.Infoln(role.GetUserID(), role.GetID(), "EnterInstanceZone fail:GetInstanceZoneID is fail")
			this.errcode = cs_message.EnumType_ERROR
			this.user.EndTrans(this)
			return
		}

		instanceZone := role.EnterInstanceZone(battleLevel.BattleLevelID, com_type.InstanceZone_YhBattleGround)
		if instanceZone == nil {
			node_game.Infoln(role.GetUserID(), role.GetID(), "EnterInstanceZone fail:InitInstanceZone is fail")
			this.errcode = cs_message.EnumType_ERROR
			this.user.EndTrans(this)
			return
		}

		//奖励翻倍
		BattleLevelDef := table_BattleLevel.Table_.IDMap[battleLevel.BattleLevelID]
		if battleGround.ExplorePower != 1 {
			instanceZone.DoubleAward(BattleLevelDef.DropPool, battleGround.ExplorePower-int32(1))
		}
		if battleGround.IsFinally() {
			instanceZone.DoubleAward(battleGround.ThroughDropPool, int32(1))
		}

		this.EnterInstanceZoneOK(role)

	} else if IZDef.Type == com_type.InstanceZone_Boss {
		bossZone := role.GetRoleBossZone().GetCurrentEnter()
		if bossZone == nil || bossZone.BattleLevelID != msg.GetInstanceZoneID() {
			node_game.Infoln(role.GetUserID(), role.GetID(), "EnterInstanceZone fail: msg.GetInstanceZoneID is fail or bossZone is nil")
			this.errcode = cs_message.EnumType_ERROR
			this.user.EndTrans(this)
			return
		}
		instanceZone := role.EnterInstanceZone(msg.GetInstanceZoneID(), com_type.InstanceZone_Boss)
		if instanceZone == nil {
			node_game.Infoln(role.GetUserID(), role.GetID(), "EnterInstanceZone fail:InitInstanceZone is fail")
			this.errcode = cs_message.EnumType_ERROR
			this.user.EndTrans(this)
			return
		}
		this.EnterInstanceZoneOK(role)
	} else if IZDef.Type == com_type.InstanceZone_Mission {
		mission := role.GetRoleMission().GetMissionByCond(msg.GetInstanceZoneID(), com_type.Mission_InstanceZone)
		if mission == nil {
			node_game.Infoln(role.GetUserID(), role.GetID(), "EnterInstanceZone fail:no mission ")
			this.errcode = cs_message.EnumType_ERROR
			this.user.EndTrans(this)
			return
		}

		//读表 前置条件
		//前置关卡
		//preLevel := IZDef.PreconditionLevel

		if role.GetWeapon1() == 0 {
			node_game.Infoln(role.GetUserID(), role.GetID(), "EnterInstanceZone fail:no weapon")
			this.errcode = cs_message.EnumType_ERROR
			this.user.EndTrans(this)
			return
		}

		ap, _ := role.GetRoleAttr().GetAttr(attr.ActionPoint)
		gold, _ := role.GetRoleAttr().GetAttr(attr.Gold)
		diamond, _ := role.GetRoleAttr().GetAttr(attr.Diamond)

		if ap < int64(IZDef.ActionPointCost) || gold < int64(IZDef.GoldCost) || diamond < int64(IZDef.DiamondCost) {
			node_game.Infoln(role.GetUserID(), role.GetID(), "EnterInstanceZone fail:cost not enough")
			this.errcode = cs_message.EnumType_ERROR
			this.user.EndTrans(this)
			return
		}

		for _, v := range IZDef.ItemCost {
			if v.ItemID != 0 && v.ItemCount != 0 {
				if role.GetRoleItem().GetItem(v.ItemID).ItemCount < v.ItemCount {
					node_game.Infoln(role.GetUserID(), role.GetID(), "EnterInstanceZone fail:cost not enough")
					this.errcode = cs_message.EnumType_ERROR
					this.user.EndTrans(this)
					return
				}
			}
		}

		role.EnterInstanceZone(msg.GetInstanceZoneID(), com_type.InstanceZone_Mission)

		instanceZone := role.GetInstanceZone()
		if instanceZone == nil {
			node_game.Infoln(role.GetUserID(), role.GetID(), "EnterInstanceZone fail:Init InstanceZone is fail")
			this.errcode = cs_message.EnumType_ERROR
			this.user.EndTrans(this)
			return
		}

		//扣除消耗
		role.UseActionPoint(int64(IZDef.ActionPointCost))
		instanceZone.ActionPointCost = IZDef.ActionPointCost
		role.UseGold(int64(IZDef.GoldCost))
		instanceZone.GoldCost = IZDef.GoldCost
		role.UseDiamond(int64(IZDef.DiamondCost))
		instanceZone.DiamondCost = IZDef.DiamondCost

		for _, v := range IZDef.ItemCost {
			if v.ItemID != 0 && v.ItemCount != 0 {
				role.GetRoleItem().UseItem(v.ItemID, v.ItemCount)
				instanceZone.ItemCost[v.ItemID] = v.ItemCount
			}
		}
		role.OnItemDirty()
		//战斗属性验证
		//role.TotalBattleAttr()

		this.EnterInstanceZoneOK(role)
	}
}

func (this *transactionEnterInstanceZone) EnterInstanceZoneOK(role *role.Role) {
	this.resp = role.GetInstanceZone().PackAllAward()

	node_game.Infoln(role.GetUserID(), role.GetID(), "EnterInstanceZone OK")
	this.errcode = cs_message.EnumType_OK
	this.user.EndTrans(this)
}

func (this *transactionEnterInstanceZone) End() {
	if this.errcode == cs_message.EnumType_OK {
		msg := this.req.GetData().(*cs_message.EnterInstanceZoneToS)

		mapID := table_BattleLevel.Table_.IDMap[msg.GetInstanceZoneID()].MapID
		pos := table_BattleLevel.Table_.IDMap[msg.GetInstanceZoneID()].Position
		anglge := table_BattleLevel.Table_.IDMap[msg.GetInstanceZoneID()].Angle

		this.resp.Errcode = cs_message.EnumType(cs_message.EnumType_OK).Enum()
		this.resp.MapID = proto.Int32(mapID)
		this.resp.Position = &cs_message.Position{
			X: proto.Int32(pos.X),
			Y: proto.Int32(pos.Y),
			Z: proto.Int32(pos.Z),
		}
		this.resp.Angle = proto.Int32(anglge)
	} else {
		this.resp = &cs_message.EnterInstanceZoneToC{
			Errcode: cs_message.EnumType(this.errcode).Enum(),
		}
	}
	this.user.Reply(this.req.GetSeriNo(), this.resp)
}

func (this *transactionEnterInstanceZone) Timeout() {
	this.errcode = cs_message.EnumType_RETRY
	this.user.EndTrans(this)
}

func init() {
	user.RegisterTransFunc(&cs_message.EnterInstanceZoneToS{}, func(user *user.User, msg *codecs.Message) transaction.Transaction {
		return &transactionEnterInstanceZone{
			user: user,
			req:  msg,
		}
	})
}
